<?php

namespace app\common\model\banxi\student;

use app\common\enums\AccountTypeEnum;
use app\common\enums\SexEnum;
use app\common\enums\StudentStatusEnum;
use app\common\model\banxi\core\CoreAccountClassHour;
use app\common\model\banxi\Grade;
use app\common\model\banxi\organization\Organization;
use app\common\model\banxi\trainer\Trainer;
use app\common\model\common\BaseModel;
use app\common\service\ConfigService;
use app\common\service\core\CoreAccountClassHourService;
use think\db\exception\PDOException;
use think\Exception;
use think\exception\ValidateException;
use think\Model;
use think\model\concern\SoftDelete;

/**
 * 学员
 */
class Student extends BaseModel
{
    use SoftDelete;

    protected $name = 'banxi_student';

    protected $autoWriteTimestamp = true;

    protected $deleteTime = 'del';

    protected $defaultSoftDelete = 0;

    protected $append = [
        'sexCn',
        'statusCn'
    ];

    protected $type = [
        'id' => 'string',
        'del' => 'string',
        'gradeId' => 'string',
        'teachTrainerId' => 'string',
        'wordRemember' => 'boolean',
        'createTime' => 'timestamp:Y-m-d H:i:s',
        'updateTime' => 'timestamp:Y-m-d H:i:s',
    ];

    //-----------------------------------------------------------------------------------
    //-                                    获取器                                      -
    //-----------------------------------------------------------------------------------
    public function getSexCnAttr(int|null $value, array $data): string
    {
        $value = $value ?: ($data['sex'] ?? '');
        return (new SexEnum())->getDescription($value) ?? '';
    }

    public function getStatusCnAttr(int|null $value, array $data): string
    {
        $value = $value ?: ($data['status'] ?? '');
        return (new StudentStatusEnum())->getDescription($value) ?? '';
    }

    //-----------------------------------------------------------------------------------
    //-                                    处理方法                                      -
    //-----------------------------------------------------------------------------------

    //获取用户信息(昵称/手机号)
    public static function getByAccountOrPhone(string $account): array|Model|Student|null
    {
        return self::where(['account|phone' => $account])->find();
    }

    public function getOrganizationStudent($organizationId)
    {
        return self::where(['organizationId' => $organizationId])->column('id');
    }

    public static function getByPhone(string $phone): array|Model|Student|null
    {
        return self::where(['phone' => $phone])->find();
    }

    public static function getById(int $id): array|Model|Student|null
    {
        return self::where(['id' => $id])->find();
    }

    public static function getUserInfo(int $id, array $with = []): array|Model|Student|null
    {
        return self::where(['id' => $id])->with($with)->find();
    }

    //通过openid获取用户信息
    public static function getByOpenid(string $openid): array|Model|Student|null
    {
        return self::where(['weMiniOpenid' => $openid])->find();
    }

    public static function getNameById(int $id): array|Model|Student|null|string
    {
        $student = self::where(['id' => $id])->find();
        return $student ? $student['name'] : null;
    }

    //获取列表
    public function getListPage(array $where, string $page = '1', int $limit = 10): \think\Paginator
    {
        return self::where($where)
            ->with([
                'accountClassHour',
                'organizationBaseInfo' => function ($query) {
                    $query->field('id,name,managerName');
                },
                'gradeInfo',
                'teachTrainerInfo' => function ($query) {
                    $query->field('id,name');
                }
            ])
            ->order(['id' => 'desc'])
            ->paginate([
                'page' => $page,
                'list_rows' => $limit,
            ])->each(function ($item) {
                if ($item['organizationId'] == 0) {
                    $organizationModel = new Organization();
                    $item['organizationBaseInfo'] = $organizationModel->getOrganizationInfo();
                }
            });

    }

    //获取列表(用于下拉选择)
    public function getListSelectPage(array $where, string $page = '1', int $limit = 10): \think\Paginator
    {
        return self::where($where)
            ->order(['id' => 'desc'])
            ->field('id,name,avatar')
            ->paginate([
                'page' => $page,
                'list_rows' => $limit,
            ]);

    }

    //获取列表(用于下拉选择课时)
    public function getListSelectClassHourPage(int|string $courseFullType, array $where, string $page = '1', int $limit = 10)
    {

        // 处理where条件中的organizationId，添加表别名以避免歧义
        foreach ($where as &$condition) {
            if (is_array($condition) && isset($condition[0]) && $condition[0] === 'organizationId') {
                $condition[0] = 'a.organizationId';
            }
            if (is_array($condition) && isset($condition[0]) && $condition[0] === 'id') {
                $condition[0] = 'a.id';
            }
        }
        unset($condition);
        if (in_array($courseFullType, [1, 2])) {
            if ($courseFullType == 1) {
                $field = ['a.id,a.name,a.organizationId,b.class30Minute as classMinuteNum,b.class30MinuteFreeze as classMinuteFreezeNum'];
                $where[] = ['b.class30Minute', '>', 0];
            } else {
                $field = ['a.id,a.name,a.organizationId,b.class60Minute as classMinuteNum,b.class60MinuteFreeze as classMinuteFreezeNum'];
                $where[] = ['b.class60Minute', '>', 0];
            }

            $list = $this->alias('a')->join('banxi_core_account_class_hour b', 'a.id = b.studentId')
                ->where($where)
                ->field($field)
                ->paginate([
                    'page' => $page,
                    'list_rows' => $limit,
                ])->each(function ($item) {
                    $item['classMinute'] = $item['classMinuteNum'] - $item['classMinuteFreezeNum'];
                });
        } else {
            $list = $this->alias('a')->field('id,name,organizationId,1 as classMinuteNum,0 as classMinuteFreezeNum')
                ->where($where)
                ->paginate([
                    'page' => $page,
                    'list_rows' => $limit,
                ])->each(function ($item) {
                    $item['classMinute'] = $item['classMinuteNum'] - $item['classMinuteFreezeNum'];
                });

        }

        return $list;
    }

    //获取信息
    public function getInfo(array $where): array|Model|null
    {
        return $this->with([
            'accountClassHour',
            'extraInfo',
            'organizationBaseInfo' => function ($query) {
                $query->field('id,name');
            }, 'gradeInfo',
            'teachTrainerInfo' => function ($query) {
                $query->field('id,name');
            }])->where($where)->find();
    }

    /**
     * 新增/更新
     * @param $organizationId
     * @param $data
     * @param $dealUser
     * @return true
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function saveOrUpdate(array $data, string $organizationId = "0"): bool
    {
        self::startTrans();
        try {
            $id = $data['id'] ?? null;
            $saveData = $data;
            if (!$id) {
                if (!isset($saveData['organizationId'])) {
                    $saveData['organizationId'] = $organizationId;
                }
                $saveData['recommendCode'] = createRandomString('SDF');
                $salt = createPasswordSalt();
                $password = $data['password'] ?? substr($data['phone'], -6);
                $saveData['salt'] = $salt;
                $saveData['password'] = createPassword($salt, $password);
                $student = new self();
            } else {
                $student = self::where('id', $id)->find();
                if (empty($student)) {
                    throw new ValidateException('学员不存在');
                }
                if (!empty($data['passwordUpdate'])) {
                    $salt = createPasswordSalt();
                    $saveData['salt'] = $salt;
                    $saveData['password'] = createPassword($salt, $data['passwordUpdate']);
                }
                $saveData['weMiniOpenid'] = $student['weMiniOpenid'];
            }
            $saveData['account'] = $data['account'] ?? '';
            $saveData['account'] = $this->createAccount($saveData['account'], $id);
            $birthday = $data['birthday'] ?? 0;
            $age = 0;
            if ($birthday) {
                $age = calculateAge($birthday);
            }
            $saveData['age'] = $age;
            $saveData['avatar'] = $data['avatar'] ?? '';
            if (!$saveData['avatar']) {
                $configService = new ConfigService();
                $saveData['avatar'] = $configService->getSysConfigValue('default_avatar');
            }
            $isExists = self::where('phone', $data['phone'])
                    ->where('id', '<>', $id)
                    ->count() > 0;
            if ($isExists) {
                throw new ValidateException('手机号已存在,请更换后重试');
            }
            $student->save($saveData);
            $studentExtra = StudentExtra::where('studentId', $student->id)->find();
            $extraSaveData = $data['extraInfo'];
            $extraSaveData['studentId'] = $student->id;
            $extraSaveData['organizationId'] = $organizationId;
            if ($id == null) {
                $studentExtra = new StudentExtra();
                $studentExtra->save($extraSaveData);
                $accountClassHourService = new CoreAccountClassHourService();
                $accountClassHourService->getByAccountIdAndType($student->id, AccountTypeEnum::STUDENT);
            } else {
                $studentExtra->save($extraSaveData);
            }
            self::commit();
        } catch (ValidateException|PDOException|Exception $e) {
            self::rollback();
            throw new ValidateException($e->getMessage());
        }
        return true;
    }

    public function createAccount($account = '', $id = null)
    {
        if (empty($account)) {
            // 自动生成账号
            $maxAttempts = 10;
            $attempts = 0;

            do {
                $account = createRandomString('XM');
                $attempts++;

                if ($attempts >= $maxAttempts) {
                    throw new ValidateException('生成账号失败，请稍后重试');
                }

                $query = $this->where('account', $account);
                if ($id) {
                    $query = $query->where('id', '<>', $id);
                }
                $isExists = $query->count() > 0;

            } while ($isExists);
        } else {
            // 检查指定账号是否已存在
            $query = $this->where('account', $account);
            if ($id) {
                $query = $query->where('id', '<>', $id);
            }
            $isExists = $query->count() > 0;

            if ($isExists) {
                throw new ValidateException('账号已存在,请更换后重试');
            }
        }

        return $account;
    }


    //启停用
    public function updateEnable(int $id)
    {
        $info = $this->where('id', $id)->find();
        if (empty($info)) {
            throw new ValidateException('操作失败，学员不存在');
        }
        $status = $info->status == 1 ? 2 : 1;
        return $this->update(['status' => $status], ['id' => $id]);

    }

    public function subSubscribeNum($studentId)
    {
        return $this->where('id', $studentId)->setDec('subscribeNum',1);
    }

    //-----------------------------------------------------------------------------------
    //-                                    模型关联                                      -
    //-----------------------------------------------------------------------------------
    public function gradeInfo()
    {
        return $this->hasOne(Grade::class, 'id', 'gradeId');
    }

    public function organizationBaseInfo()
    {
        return $this->hasOne(Organization::class, 'id', 'organizationId');
    }

    public function teachTrainerInfo()
    {
        return $this->hasOne(Trainer::class, 'id', 'teachTrainerId');
    }

    public function accountClassHour()
    {
        return $this->hasOne(CoreAccountClassHour::class, 'studentId', 'id');
    }

    public function extraInfo()
    {
        return $this->hasOne(StudentExtra::class, 'studentId', 'id');
    }


}